using System;

namespace RapidHDL
{
	/// <summary>
	/// Summary description for Mux.
	/// </summary>
	public class Mux : Component 
	{
        public NodeVector SelectNodes;
        public NodeVector[] InputNodes;
        public NodeVector OutputNodes;

        public Mux(Component poParentComponent, string psName, int piWidth, int piInputCount)
            : base(poParentComponent,psName)
		{
            int iSelWidth = Conversion.IntToBinaryString(piInputCount-1).Length;

            OutputNodes = this.CreateNodeVector("DATA_O", piWidth,NodeFlowType.Source);
            InputNodes = new NodeVector[piInputCount];
            for (int iIdx = 0; iIdx < piInputCount; iIdx++)
                InputNodes[iIdx] = new NodeVector(this, "DATA_" + iIdx.ToString() + "_I", piWidth,NodeFlowType.Sink);

            SelectNodes = this.CreateNodeVector("SEL_I", iSelWidth, NodeFlowType.Sink);
        }

        public override void CalculateOutput()
        {
            string sSel = SelectNodes.NodeVectorAsString;
            int iSel = Conversion.StringBinaryToInt(sSel);

            if (sSel.IndexOf('x') > -1)
            {
                OutputNodes.NodeVectorAsString = new string('x', OutputNodes.Nodes.Count);
                return;
            }
            
            if (iSel < InputNodes.Length)
                OutputNodes.NodeVectorAsString = InputNodes[iSel].NodeVectorAsString;
            else
                OutputNodes.NodeVectorAsString = new string('x', OutputNodes.Nodes.Count);

        }

        public override bool TransformStructureToVerilog()
        {            
            string sVerilog = "";
            string sOutputVector = "";
            
            ComponentVerilog.VerilogTraceLog("Starting To Write Mux");

            foreach (NodeVector oNodeVector in this.SourceNodeVectors.Values)
            {
                ComponentVerilog.WriteVerilogText("reg " + oNodeVector.Name + ";", 3);
            }
            ComponentVerilog.WriteVerilogSkip();


            sVerilog = "always @(SEL_I,";
            foreach (NodeVector oNodeVector in this.InputNodes)
            {
                sVerilog += oNodeVector.Name + ",";
            }
            sVerilog = sVerilog.Remove(sVerilog.Length - 1, 1) + ")";

            ComponentVerilog.WriteVerilogText(sVerilog);
            ComponentVerilog.WriteVerilogText("begin");

            sVerilog = "case (" + SelectNodes.Name + ")";
            ComponentVerilog.WriteVerilogText(sVerilog, 1);

            sOutputVector = OutputNodes.Name;

            for (int iIdx = 0; iIdx < InputNodes.Length; iIdx++)
            {
                sVerilog = SelectNodes.Nodes.Count.ToString() + "'b" + Conversion.IntToBinaryString(iIdx, SelectNodes.Nodes.Count);
                sVerilog += " : " + sOutputVector + " <= ";
                sVerilog += InputNodes[iIdx].Name + ";";
                ComponentVerilog.WriteVerilogText(sVerilog, 3);
            }
            
            string sX = new string('x',OutputNodes.Nodes.Count);
            sVerilog = "default : " + sOutputVector + " <= " + OutputNodes.Nodes.Count.ToString() + "'b" + sX + ";";
            ComponentVerilog.WriteVerilogText(sVerilog,3);
            
            ComponentVerilog.WriteVerilogText("endcase", 1);
            ComponentVerilog.WriteVerilogText("end");
            return true;
        }


    }
}
